home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
COMMUNIC
/
1572C.ZIP
/
KMT_IBM_.ZIP
/
MSSRCV.ASM
Wrap
Assembly Source File
|
1989-07-11
|
52KB
|
1,016 lines
NAME mssrcv
; File MSSRCV.ASM
; Edit history
; Last edit 24 Nov 1988
; 24 Nov 1988 Add 100% screen msg done upon successful file reception.
; 21 Nov 1988 Version 2.32
; 12 Nov 1988 Modify disk space arithmetic for DOS 4 # sectors > 64K.
; 4 Aug 1988 Correct filesize test for attributes packets. Let ioctl tell
; us the block device ident (for bridged or joined drives), from Henrik
; Levokwetz.
; 1 July 1988 Version 2.31
; 12 June 1988 Add error recovery if serial port does not initialize.
; 31 May 1988 Use proc spchk to check available disk space
; when using file attributes.
; 15 May 1988 Add kstatus global status word
; 23 Feb 1988 Add Mail command. [jrd]
; 14 Feb 1988 Add Attributes packets. [jrd]
; 27 Jan 1988 Remove serrst call, done now in mssker idle loop. [jrd]
; 7 Jan 1988 Check for Control-E condition before sending a NAK. [jrd]
; 1 Jan 1988 version 2.30
; 26 Dec 1987 Clean out unused pack.oldtry, etc., clean up. [jrd]
; 6 Dec 1987 Flush last disk buffer when aborting a transfer. [jrd]
; 8 Oct 1987 Ensure error pkts use 1 byte chksum at init stage. [jrd]
; 27 Aug 1987 Add tests for receiving to screen for error reports [jrd]
; 23 July 1987 Add buffer clear after opening new output file. [jrd]
; 7 June 1987 Add DOS errlev return of 2 for failure to receive. [jrd]
; 7 May 1987 Correct placement of begtim and endtim statistics calls. [jrd]
; 19 Oct 1986 Fix Rinit to use 1 byte checksums on Naks to S packets.
; 1 Oct 1986 Version 2.29a
; 17 Sept 1986 Fix file not being deleted when transfer fails. [jrd]
; 14 August 1986 Allow changing EOL characters.
; 9 August 1986 Allow Control-X/Z exit while getting 'S' packet. [jrd]
; 27 July 1986 Clear file opened flag to prevent unwanted closing of stdin.
; 16 June 1986 Add clearing of "flags.getflg" under read0: to prevent missing
; initial packet read for REC commands. [jrd]
; 26 May 1986 Revise code to permit serial display. [jrd]
; [2.29] code frozen on 6 May 1986 [jrd]
public read12, read2, rin21, rfile3, read, updrtr, nak, rrinit
include mssdef.h
datas segment public 'datas'
extrn data:byte, bufpnt:word, chrcnt:word, curchk:byte, fmtdsp:byte
extrn flags:byte, pack:byte, trans:byte, dtrans:byte
extrn diskio:byte, locfil:byte, maxtry:byte, imxtry:byte
extrn fsta:word, errlev:byte, ofilsz:word, kstatus:word
setattr equ 57h ; DOS get/set file's date and time
ermes7 db '?Unable to receive initiate-packet$'
ermes8 db '?Unable to receive file name$'
ermes9 db '?Unable to receive end of file$'
erms10 db '?Unable to receive data$'
erms11 db 'Not enough disk space for file$'
infms1 db cr,' Receiving: In progress',cr,lf,'$'
infms3 db 'Completed',cr,lf,'$'
infms4 db 'Failed',cr,lf,'$'
infms6 db 'Interrupted',cr,lf,'$'
donemsg db '100%$'
filhlp2 db ' Local path or filename or carriage return$'
ender db bell,bell,'$'
crlf db cr,lf,'$'
temp dw 0
filopn db 0 ; Says if disk file is open
ftime db 0,0 ; file time (defaults to 00:00:00)
fdate db 0,0 ; file date (defaults to 1 Jan 1980)
attrib db 0 ; attribute code causing file rejection
datas ends
code segment public 'code'
extrn gofil:near, outbuf:near, comnd:near
extrn spack:near, rpack:near, serini:near, serrst:near
extrn spar:near, rpar:near, init:near, cxmsg:near, perpos:near
extrn error:near, error1:near, ptchr:near, erpos:near, rtpos:near
extrn stpos:near, rprpos:near, nppos:near, nout:near
extrn dodec:near, doenc:near, errpack:near, intmsg:near
extrn send11:near, clrmod:near, ihostr:near
extrn begtim:near, endtim:near, pktsize:near,strlen:near,strcpy:near
assume cs:code, ds:datas
; Update retry count and fall through to send a NAK
NAK0: call updrtr ; Update retry count
nak1: cmp flags.cxzflg,'E' ; Protocol abort sign?
jne nak2 ; ne = no
ret ; return to do current ('A') state
nak2: cmp flags.cxzflg,'C' ; Control-C abort?
jne nak ; ne = no
mov pack.state,'A' ; set Abort state
ret
NAK: mov ax,pack.pktnum ; Get the packet number we're waiting for
mov pack.seqnum,ax
mov pack.datlen,0 ; no data
add fsta.nakscnt,1 ; count NAKs sent
mov ah,'N' ; NAK that packet
call spack
jmp abort ; failed
nop
ret
updrtr: cmp pack.state,'A' ; Supposed to abort?
je upd0 ; Yes, don't bother with retry count
inc pack.numrtr ; Increment the number of retries
cmp flags.xflg,1 ; Writing to screen?
je upd0 ; e = yes, skip this
cmp pack.numrtr,0 ; non-zero item to display?
je upd0 ; nothing to display
push ax ; save packet type in ah
call rtpos ; Position cursor
mov ax,pack.numrtr
call nout ; Write the number of retries
pop ax ; recover packet type in ah
upd0: ret
; Abort
ABORT PROC NEAR
cmp filopn,0 ; Disk file open?
je abort0 ; e = no so don't close
cmp flags.xflg,1 ; Writing to the screen?
je abort0 ; Yes, don't close "file"
call outbuf ; flush last buffer to disk, ignore errors
nop
nop
nop
mov ah,close2 ; DOS 2.0 file close
push bx
mov bx,diskio.handle ; file handle
int dos
pop bx
mov filopn,0 ; say file is no longer open
cmp flags.abfflg,0 ; save file after closing?
je abort0 ; e = yes
push dx
mov dx,offset diskio.string ; get back file name
mov ah,del2 ; delete the file
int dos
pop dx
abort0: mov pack.state,'A' ; Otherwise abort
mov byte ptr locfil,0 ; clear local filename
or errlev,2 ; set DOS error level
or fsta.xstatus,2 ; set status
mov kstatus,2 ; global status
xor ax,ax ; tell statistics this is a receive operation
call endtim ; stop file timer
ret
ABORT ENDP
ackpak proc near ; send an ACK packet
mov ah,'Y' ; ack packet
call spack
jmp abort ; failed
nop
ret
ackpak endp
; init variables for read...
rrinit proc near
mov pack.numpkt,0 ; Set the number of packets to zero
mov pack.numrtr,0 ; Set the number of retries to zero
mov pack.pktnum,0 ; Set the packet number to zero
mov pack.numtry,0 ; Set the number of tries to zero
mov filopn,0 ; say no file opened yet
ret
rrinit endp
; RECEIVE command -- Some code moved to the GET routine
READ PROC NEAR
mov flags.nmoflg,0 ; Override file name from other host
mov bx,offset filhlp2 ; Text of help message
mov dx,offset locfil ; local file name string
mov byte ptr locfil,0 ; clear it first
mov ah,cmfile ; allow path names
call comnd
ret
nop
nop
cmp ah,0 ; was an override filename given?
je read0 ; e = no
mov flags.nmoflg,1 ; yes, set flag = use this filename
read0: mov ah,cmcfm ; Get a confirm
call comnd
ret
nop
nop
mov pack.state,'R' ; Set the state to receive initiate
mov flags.getflg,0 ; Reset flag (not a Get command)
mov flags.xflg,0
call serini ; initialize serial port
jnc read0b ; nc = success
or errlev,2 ; set DOS error level
or fsta.xstatus,2 ; set status, failed
or kstatus,2 ; global status
test flags.remflg,dquiet ; quiet display mode?
jnz read0a ; nz = yes. Don't write to screen
mov ah,prstr
mov dx,offset infms4 ; Failed message
int dos
read0a: ret ; return failure
read0b: call rrinit ; init variables for read
call init ; setup display form
call ihostr ; initialize the host
READ12: ; Called by GET & SRVSND, display ok
mov kstatus,0 ; global status, success
call begtim ; start next statistics group
mov flags.cxzflg,0 ; Reset ^X/^Z flag
mov ah,trans.chklen ; get desired checksum length
mov curchk,ah ; and remember it here
test flags.remflg,dquiet ; quiet display mode?
jnz read2 ; nz = yes, no printing
cmp flags.destflg,2 ; Receiving to the screen?
je read21 ; e = yes, no formatted display
call stpos
mov ah,prstr ; Be informative
mov dx,offset infms1
int dos
test flags.remflg,dserial ; serial display mode?
jnz read2 ; nz = yes, skip initial retry display
call rtpos ; Position cursor
mov ax,pack.numrtr
call nout ; Write the number of retries
READ2: ; Called by GENERIC server command dispatcher
cmp flags.xflg,1 ; Are we receiving to the screen?
je read21 ; e = skip the screen stuff
call nppos ; Position cursor for number of packets msg
mov ax,pack.numpkt
call nout ; Write the number of packets
read21: mov ah,pack.state ; Get the state
cmp ah,'D' ; Data receive state?
jne read3
call rdata ; yes, get data packets
jmp read2
read3: cmp ah,'F' ; File receive state?
jne read4
call rfile ; Call receive file
jmp read2
read4: cmp ah,'R' ; Receive initiate state?
jne read5 ; ne = no
call rinit
jmp read2
; Receive Complete state processor
read5: push ax ; save status in ah
cmp flags.cxzflg,0 ; Completed or interrupted?
je read5a ; e = ended normally
or errlev,2 ; set DOS error level
or fsta.xstatus,2+80h ; set status, failed + intervention
or kstatus,2+80h ; global status
read5a: push ax
xor ax,ax ; tell statistics this is a receive operation
call endtim ; stop file timer
pop ax
mov ah,curchk ; get working checksum
mov trans.chklen,ah ; and restore for next file
mov byte ptr locfil,0 ; clear local filename
pop ax ; recover status in ah
mov dx,offset infms3 ; Completed message
cmp ah,'C' ; Receive complete state?
je read6 ; e = yes, else receive failed
or errlev,2 ; set DOS error level
or fsta.xstatus,2 ; set status, failed
or kstatus,2 ; global status
mov dx,offset infms4 ; Failed message
cmp filopn,2 ; file still open?
jne read6 ; ne = no
push dx
call abort ; close file & maybe delete
pop dx
read6: cmp flags.xflg,0 ; Did we write to the screen?
je read6a ; e = no, so print status
cmp flags.destflg,2 ; Receiving to screen?
je read6d ; Yes don't reset
mov flags.xflg,0 ; Reset it
jmp read6d ; Yes, so just return
read6a: test flags.remflg,dquiet ; quiet display mode?
jnz read6d ; nz = yes, keep going
cmp flags.destflg,2 ; Receiving to the screen?
je read6d ; e = yes, no formatted display
push dx ; save message pointer
call stpos ; Position cursor
pop dx
mov ah,prstr
cmp flags.cxzflg,0 ; Completed or interrupted?
je read6b ; Ended normally
mov dx,offset infms6 ; Say was interrupted
read6b: int dos
cmp flags.belflg,0 ; Bell desired?
je read6c ; No
mov dx,offset ender ; Ring them bells
int dos
read6c: test flags.remflg,dserial ; serial display?
jnz read6d ; nz = yes
call clrmod ; clear Mode Line
call rprpos ; Put prompt here
read6d: jmp rskp
READ ENDP
; Receive routines
; Receive init
RINIT PROC NEAR
mov ah,pack.numtry ; Get the number of tries
cmp ah,imxtry ; Reached the maximum number of tries?
jl rinit2
mov dx,offset ermes7
test flags.remflg,dquiet ; quiet display mode?
jnz rinit1 ; nz = yes. Don't write to screen
cmp flags.destflg,2 ; Receiving to the screen?
je rinit1 ; e = yes, no formatted display
call erpos ; Position cursor
mov ah,prstr
int dos ; Print an error message
rinit1: mov bx,dx
mov ah,trans.chklen
mov curchk,ah ; Store checksum length we want to use
mov trans.chklen,1 ; Send init checksum is always 1 char
call errpack ; Send error packet just in case
mov ah,curchk
mov trans.chklen,ah ; Reset to desired value
jmp abort ; Change the state to abort
rinit2: inc ah ; Increment it
mov pack.numtry,ah ; Save the updated number of tries
mov ah,flags.getflg ; Get cmd? (holds get pkt type in ah)
cmp ah,0 ; Have we already read in the packet?
jne rin21a ; ne = yes, so don't call RPACK
mov ah,dtrans.seol ; restore default end-of-line char
mov trans.seol,ah
mov ah,trans.chklen
mov curchk,ah ; Save checksum length we want to use
mov trans.chklen,1 ; Use 1 char for init packet
call rpack ; Get a packet
jmp rin22 ; Trashed packet: nak, retry
call pktsize ; report packet size
push ax
mov ah,curchk
mov trans.chklen,ah ; Reset to desired value
pop ax
cmp flags.cxzflg,0 ; does the user want out now?
jne rinit4 ; ne = yes, quit
rin21a: cmp ah,'S' ; Is it a send initiate packet?
jne rinit3 ; If not see if its an error
rin21: mov flags.getflg,0 ; Reset flag
mov pack.numtry,0 ; Reset the number of tries
mov ax,pack.seqnum ; Returned packet number. (Synchronize them.)
inc ax ; Increment it
and ax,3FH ; Turn off the two high order bits
mov pack.pktnum,ax ; Save modulo 64 of the number
inc pack.numpkt ; Increment the number of packets
mov ax,pack.datlen ; Get the number of arguments received
mov bx,offset data ; Get a pointer to the data
call spar ; Get data into the proper variables
mov bx,offset data ; Get a pointer to our data block
call rpar ; Set up the receive parameters
xchg ah,al
mov ah,0
mov pack.datlen,ax ; Store returned number of arguments
mov ah,trans.chklen ; Checksum length we'll use
mov curchk,ah ; Save it
mov trans.chklen,1 ; Use 1 char for init packet
call ackpak ; acknowledge the packet
mov ah,curchk ; Checksum length we'll use
mov trans.chklen,ah ; Reset to desired value
mov pack.state,'F' ; Set the state to file send
ret
rin22: call nak0 ; nak the packet
mov ah,curchk ; and only now change checksum from 1
mov trans.chklen,ah ; Reset to desired value
ret ; try again
rinit3: cmp ah,'M' ; Message packet?
jne rinit3e ; ne = no
call dodec ; decode it
call error1 ; display it
ret
rinit3e: cmp ah,'E' ; Is it an error packet?
jne rinit4 ; ne = no
call error ; yes
rinit4: jmp abort
RINIT ENDP
; Receive file
RFILE PROC NEAR
mov dl,maxtry
cmp pack.numtry,dl ; Have we reached the maximum number of tries?
jl rfile1
mov dx,offset ermes8
jmp rcverr ; do error exit
rfile1: inc pack.numtry ; Save the updated number of tries
call rpack ; Get a packet
jmp nak0 ; Trashed packet: nak, retry
call pktsize ; report packet size
cmp ah,'S' ; Is it a send initiate packet?
je rfil10
cmp ah,'I' ; An Initialization packet?
je rfil10 ; e = yes, don't decode it
call dodec ; Decode all other incoming packets
jmp rfile2 ; No, try next type
rfil10: mov dl,imxtry ; S and I packets
cmp pack.numtry,dl ; Reached the maximum number of tries?
jl rfil12 ; If not proceed
mov dx,offset ermes7
jmp rcverr ; do error exit
rfil12: mov ax,pack.pktnum ; Get the present packet number
dec ax ; Decrement
and ax,3fh ; do module 64
cmp ax,pack.seqnum ; Is the packet's number one less than now?
je rfil13
jmp nak0 ; No, NAK and try again
rfil13: mov pack.numtry,0 ; Reset the number of tries
mov bx,offset data ; Get a pointer to our data block
call rpar ; Set up the parameter information
xchg ah,al
mov ah,0
mov pack.datlen,ax ; Save the number of arguments
jmp ackpak ; acknowledge the packet
rfile2: cmp ah,'Z' ; Is it an EOF packet?
jne rfile3 ; No, try next type
mov dl,maxtry ; Z packets
cmp pack.numtry,dl ; Have we reached the maximum number of tries?
jl rfil21 ; If not proceed
mov dx,offset ermes9
jmp rcverr ; do error exit
rfil21: mov ax,pack.pktnum ; Get the present packet number
dec ax ; Decrement
and ax,3fh ; do modulo 64
cmp ax,pack.seqnum ; Is the packet's number one less than now?
je rfil24
jmp nak0 ; No, NAK and try again
rfil24: mov pack.numtry,0
mov pack.datlen,0 ; No data. (The packet number is in seqnum.)
jmp ackpak ; acknowledge the packet
rfile3: cmp ah,'F' ; Start of file (F or X packet)?
je rfil31 ; e = yes
cmp ah,'X' ; Text header packet?
jne rfile4 ; Neither one.
mov flags.xflg,1 ; 'X', say receiving to the screen
rfil31: mov ax,pack.seqnum ; Get the packet number
cmp ax,pack.pktnum ; Is it the right packet number?
je rfil32
jmp nak1 ; No, NAK it and try again
rfil32: inc ax ; Increment the packet number
and ax,3FH ; Turn off the two high order bits
mov pack.pktnum,ax ; Save modulo 64 of the number
inc pack.numpkt ; Increment the number of packets
mov filopn,0 ; assume not writing to a disk file
call dodec ; Decode incoming packet for filename
call gofil ; Get a file to write to
jmp abort
mov chrcnt,maxpack ; reset output buffer to be empty
cmp flags.xflg,0 ; writing to a disk file?
jne rfil32a ; ne = no
mov filopn,2 ; Disk file open for writing
rfil32a:
test flags.remflg,dserial ; serial display mode?
jz rfil33 ; z = no
mov ah,prstr
mov dx,offset crlf ; display cr/lf
int dos
rfil33:
mov pack.state,'D' ; Set the state to data receive
mov pack.numtry,0 ; Reset the number of tries
mov pack.datlen,0 ; No data. (The packet number is in seqnum.)
jmp ackpak ; acknowledge the packet
rfile4: cmp ah,'B' ; End of transmission?
jne rfile5 ; ne = no
mov ax,pack.pktnum
cmp ax,pack.seqnum ; Do we match?
je rfil41
jmp nak1 ; No, NAK it and try again
rfil41: mov pack.state,'C' ; Set the state to complete
mov pack.datlen,0 ; No data. (Packet number already in seqnum)
jmp ackpak ; acknowledge the packet
rfile5: cmp ah,'M' ; Message packet?
jne rfile5e ; ne = no
call dodec ; decode it
jmp error1 ; display it and return
rfile5e:cmp ah,'E' ; Is it an error packet?
jne rfile6 ; ne = no
call error
rfile6: jmp abort
RFILE ENDP
; Get file attributes from packet
; Recognize file size in bytes and kilobytes (used if bytes missing),
; file time and date. Reject Mail commands. Return carry clear for success,
; carry set for failure. If rejecting place reason code in byte temp.
GETATT PROC NEAR
mov bx,offset data ; pointer
getat0: push bx
sub bx,offset data
cmp bx,pack.datlen ; are we beyond end of data?
pop bx
jl getat1 ; l = not yet
clc
ret ; has carry clear for success
getat1: cmp byte ptr [bx],'1' ; byte length field?
jne getat2 ; ne = no
mov al,[bx] ; remember attribute
mov attrib,al
inc bx ; pointer
call getas ; get file size
call spchk ; check available disk space
jnc getat0
ret ; return failure
getat2: cmp byte ptr [bx],'!' ; kilobyte length field?
jne getat3 ; ne = no
mov al,[bx] ; remember attribute
mov attrib,al
inc bx ; pointer
call getak ; get file size
jc getat5;;;2a ; carry means decode rejected
call spchk ; check available disk space
jnc short getat0
getat2a:ret ; return failure
getat3: cmp byte ptr [bx],'#' ; date field?
jne getat4 ; ne = no
mov al,[bx] ; remember attribute
mov attrib,al
inc bx
call getatd ; get file date
jmp short getat0
getat4: cmp byte ptr [bx],'+' ; Disposition?
jne getat5 ; ne = no
mov al,[bx] ; remember attribute
mov attrib,al
cmp byte ptr [bx+2],'M' ; Mail indicator
jne getat5 ; ne = no, ignore field
stc ; set carry for failure
ret
getat5: inc bx ; look at length field
mov al,[bx]
sub al,' ' ; remove ascii bias
mov ah,0
inc ax ; include length field byte
add bx,ax ; skip to next attribute
jmp getat0
; Decode File length (Byte) field
getas: mov cl,[bx] ; length of file size field
inc bx ; point at file size data
sub cl,' ' ; remove ascii bias
mov ch,0
mov ax,0 ; current length, bytes
mov dx,0
getas2: push cx
shl dx,1 ; high word of size, times two
mov di,dx ; save
shl dx,1
shl dx,1 ; times 8
add dx,di ; yields dx * 10
mov di,dx ; save dx
mov dx,0
mov cx,10 ; also clears ch
mul cx ; scale up previous result in ax
mov cl,[bx] ; get a digit
inc bx
sub cl,'0' ; remove ascii bias
add ax,cx ; add to current length
adc dx,0 ; extend result to dx
add dx,di ; plus old high part
pop cx
loop getas2
mov ofilsz+2,ax ; low order word
mov ofilsz,dx ; high order word
ret
; Decode Kilobyte attribute
getak: mov ax,ofilsz+2 ; current filesize, low word
add ax,ofilsz
cmp ax,0 ; zero if not used yet
je getak1 ; e = not used before
dec bx ; backup pointer
stc ; set carry to ignore this field
ret
getak1: call getas ; parse as if Byte field
mov ax,ofilsz+2 ; get low word of size
mov dx,ofilsz ; high word
mov dh,dl ; times 256
mov dl,ah
mov ah,al
mov al,0
shl dx,1 ; times four to make times 1024
shl dx,1
rol ax,1 ; two high bits of ah to al
rol ax,1
and al,3 ; keep them
or dl,al ; insert into high word
mov al,0
mov ofilsz,dx ; store high word
mov ofilsz+2,ax ; store low word
clc ; clear carry
ret
getatd: ; File date and time
mov word ptr ftime,1 ; two seconds past midnight
mov word ptr fdate,0
mov dl,[bx] ; field length
mov dh,0
sub dl,' ' ; remove ascii bias
inc bx ; next field
add dx,bx ; where next field begins
mov temp,dx ; save in temp
mov ax,0 ; recover file date and time
mov dh,10 ; multiplier
cmp byte ptr[bx+6],' ' ; short form date (yymmdd)?
je getad2 ; e = yes
add bx,2 ; skip century digits (19)
getad2: mov ax,10
mov dx,[bx] ; get year tens and units digits
add bx,2 ; dl has tens, dh has units
sub dx,'00' ; remove ascii bias
mul dl ; ax = high digit times ten
add al,dh ; units digit
sub ax,80 ; remove rest of 1980 bias
jns getad2a ; ns = no sign = non-negative result
mov ax,0 ; don't store less than 1980
getad2a:shl al,1 ; adjust for DOS bit format
mov fdate+1,al
mov ax,[bx] ; get month digits
add bx,2
sub ax,'00' ; remove ascii bias
cmp al,0 ; tens digit set?
je getad2b ; e = no
add ah,10 ; add to units digit
getad2b:cmp ah,8 ; high bit of month set?
jb getad3 ; b = no
or fdate+1,1
sub ah,8 ; and deduct it here
getad3: mov cl,5
shl ah,cl ; normalize months bits
mov fdate,ah
mov dx,[bx] ; do day of the month
add bx,2 ; dh has units, dl has tens digit
sub dx,'00' ; remove ascii bias
mov ax,10
mul dl ; ax = ten times tens digit
add al,dh ; plus units digit
or fdate,al
cmp bx,temp ; are we at the end of this field?
jae getad5 ; ae = yes, prematurely
inc bx ; skip space separator
getad4: mov ax,10 ; prepare for hours
mov dx,[bx] ; hh digits
add bx,2
sub dx,'00' ; remove ascii bias
mul dl ; 10*high digit of hours
add al,dh ; plus low digit of hours
mov cl,3 ; normalize bits
shl al,cl
mov ftime+1,al ; store hours
inc bx ; skip colon
mov ax,10 ; prepare for minutes
mov dx,[bx] ; mm digits
add bx,2
sub dx,'00' ; remove ascii bias
mul dl ; 10*high digit of minutes
add al,dh ; plus low digit of minutes
mov ah,0
mov cl,5 ; normalize bits
shl ax,cl
or ftime+1,ah ; high part of minutes
mov ftime,al ; low part of minutes
cmp bx,temp ; are we at the end of this field
jae getad5 ; ae = yes, quit here
inc bx ; skip colon
mov ax,10 ; prepare for seconds
mov dx,[bx] ; ss digits
add bx,2
sub dx,'00' ; remove ascii bias
mul dl ; 10*high digit of seconds
add al,dh ; plus low digit of seconds
shr al,1 ; store as double-seconds for DOS
or ftime,al ; store seconds
getad5: ret
GETATT ENDP
; Receive data
RDATA PROC NEAR
mov dl,maxtry
cmp pack.numtry,dl ; Get the number of tries
jl rdata1
mov dx,offset erms10
jmp rcverr ; do error exit
rdata1: inc pack.numtry ; Save the updated number of tries
call rpack ; Get a packet
jmp nak0 ; Trashed packet: nak, retry
nop
call pktsize ; report packet size
cmp ah,'D' ; Is it a data packet?
je rdat11 ; e = yes
cmp ah,'A' ; Attributes packet?
jne rdata7 ; ne = no
mov ax,pack.pktnum
cmp ax,pack.seqnum ; Do we match?
je rdata6
jmp nak1 ; No, NAK it and try again
rdata6: call getatt ; get file attributes from packet
mov pack.numtry,0 ; Reset number of tries
jnc rdata6a ; nc = success
mov pack.datlen,2 ; 2 bytes (Packet number already in seqnum)
mov data,'N' ; Decline the transfer
mov al,attrib ; get attribute causing rejection
mov data+1,al ; report rejection reason to sender
or fsta.xstatus,2 ; set status, failed
mov kstatus,2 ; global status
jmp short rdata6b
rdata6a:mov pack.datlen,0 ; No data. (Packet number already in seqnum)
rdata6b:mov ax,pack.pktnum
inc ax ; Increment the packet number
and ax,3FH ; Turn off the two high order bits
mov pack.pktnum,ax ; Save modulo 64 of the number
inc pack.numpkt ; Increment the number of packets
jmp ackpak ; acknowledge the packet
rdata7: call dodec ; Decode data
jmp rdata2 ; try next type
; D packets
rdat11: mov ax,pack.pktnum ; Get the present packet number
cmp ax,pack.seqnum ; Is the packet's number correct?
jz rdat14
mov dl,maxtry
cmp pack.numtry,dl ; Have we reached the maximum number of tries?
jl rdat12 ; If not proceed
mov dx,offset erms10
jmp rcverr ; do error exit
rdat12: mov ax,pack.pktnum
dec ax
and ax,3fh ; do modulo 64
cmp ax,pack.seqnum ; Is the packet's number one less than now?
je rdat13
jmp nak0 ; No, NAK it and try again
rdat13: mov pack.numtry,0 ; Reset number of tries
mov pack.datlen,0 ; No data. (The packet number is in seqnum.)
jmp ackpak ; acknowledge the packet
rdat14: inc pack.pktnum ; Increment the packet number
and pack.pktnum,3fh ; Save modulo 64 of the number
inc pack.numpkt ; Increment the number of packets
mov ax,pack.datlen ; Get the length of the data
cmp flags.cxzflg,0 ; Has the user typed a ^X or ^Z?
je rdt14x ; No, write out the data
or fsta.xstatus,2+80h ; set status, failed + intervention
mov kstatus,2+80h ; global status
cmp flags.abfflg,1 ; Discard incomplete files?
je rdat15 ; If yes don't write data out to file
rdt14x: call ptchr ; decode the data and output to file
jmp abort ; Unable to write out chars; abort
rdat15: mov pack.numtry,0 ; Reset the number of tries
mov pack.datlen,0 ; No data. (Packet number still in seqnum.)
cmp flags.cxzflg,0 ; Interrupt file transfer?
je rdat16 ; Nope
or fsta.xstatus,2+80h ; set status, failed + intervention
mov kstatus,2+80h ; global status
mov bx,offset data ; Send data in ACK in case remote
mov ah,flags.cxzflg ; knows about ^X/^Z
mov [bx],ah ; Put data into the packet
mov pack.datlen,1 ; Set data size to 1
mov cx,1
call doenc
rdat16: jmp ackpak ; acknowledge the packet
rdata2: cmp ah,'F' ; Start of file?
je rdat20 ; e = yes
cmp ah,'X' ; Text header packet?
jne rdata3 ; No, try next type
rdat20: mov dl,maxtry ; F or X packet
cmp pack.numtry,dl ; Reached the max number of tries?
jl rdat21 ; If not proceed
mov dx,offset ermes8
jmp rcverr ; do error exit
rdat21: mov ax,pack.pktnum
dec ax
and ax,3fh ; modulo 64
cmp ax,pack.seqnum ; Is the packet's number one less than now?
je rdat22
jmp nak0 ; No, NAK it and try again
rdat22: mov pack.numtry,0 ; Reset number of tries
mov pack.datlen,0 ; No data. (The packet number is in seqnum.)
jmp ackpak ; acknowledge the packet
rdata3: cmp ah,'Z' ; Is it a EOF packet?
je rdat3x ; e = yes
jmp rdata4 ; Try and see if its an error
rdat3x: mov ax,pack.pktnum ; Get the present packet number
cmp ax,pack.seqnum ; Is the packet's number correct?
je rdat32
jmp nak0 ; No, NAK it and try again
rdat32: inc ax ; Increment the packet number
and ax,3FH ; Turn off the two high order bits
mov pack.pktnum,ax ; Save modulo 64 of the number
inc pack.numpkt
call dodec ; Decode incoming packet
cmp flags.cxzflg,0 ; Do we want to discard the file?
jne rdt32x ; ne = yes
cmp fmtdsp,0 ; formatted screen?
je rdat32a ; e = no, no message
mov ax,ofilsz ; high word of attributes file size
or ax,ofilsz+2 ; low word
cmp ax,0 ; was file size given by other side?
je rdat32a ; e = no
call perpos ; position cursor to percent done
mov dx,offset donemsg ; say 100%
mov ah,prstr
int dos
rdat32a:cmp pack.datlen,1 ; One piece of data?
jne rdat33 ; Nope - finish writing out file?
cmp data,'D' ; is the data "D" for discard?
jne rdat33 ; Nope - write out file
rdt32x: cmp flags.abfflg,0 ; Keep incomplete files?
je rdat33 ; Yes, go write it out
cmp flags.xflg,1 ; Writing to the screen?
je rdt32y ; Don't close "file"
cmp flags.destflg,2 ; file destination = screen?
je rdt32y ; e = yes, no file to close
push bx
mov ah,close2 ; DOS 2.0 file close
mov bx,diskio.handle ; file handle
int dos ; Kill it, ignore errors
pop bx
mov filopn,0 ; File closed now
mov dx,offset diskio.string ; get the filename
mov ah,del2 ; DOS 2.0 file delete
int dos
rdt32y: cmp flags.cxzflg,'X' ; Kill one file or all?
je rdt32ya ; e = one (^X)
jmp rdat36 ; No so leave flag alone
rdt32ya:call cxmsg ; Clear msg about interrupt
or errlev,2 ; set DOS error level
or fsta.xstatus,2+80h ; set status, failed + intervention
mov kstatus,2+80h ; global status
test flags.remflg,dquiet ; quiet display?
jnz rdt32z ; nz = yes
cmp flags.destflg,2 ; Receiving to the screen?
je rdt32z ; e = yes, no formatted display
call intmsg
rdt32z: mov flags.cxzflg,0 ; Reset - ^X only kills one file
jmp rdat36
rdat33: cmp flags.eofcz,0 ; should we write a ^Z?
jz rdat35 ; no, keep going
cmp flags.xflg,0 ; writing to a file?
jne rdat35 ; no, skip ^Z
rdt33x: cmp chrcnt,0 ; any space left in output buffer?
jg rdat34 ; g = yes
call outbuf ; Write out buffer if no room for ^Z
jmp abort
rdat34: mov cl,'Z'- 40h ; Put in a ^Z for EOF
push bx
mov bx,bufpnt ; Get the dma pointer
mov [bx],cl ; Add it
pop bx
dec chrcnt
rdat35: call outbuf ; Output the last buffer
jmp abort ; Give up if the disk is full
cmp flags.xflg,1 ; Writing to the screen?
je rdat37 ; Yes, don't close "file"
cmp flags.destflg,2 ; file destination = screen?
je rdat37 ; e = yes, no file to close
push bx ; do file attributes and close
mov cx,word ptr ftime ; new time
mov dx,word ptr fdate ; new date
mov word ptr fdate,0
mov word ptr ftime,0 ; clear current time/date attributes
mov ax,cx
or ax,dx
jz rdat35b ; z = no attributes to set
cmp cx,0 ; time set as null?
jne rdat35a ; ne = no
inc cl ; two seconds past midnight
rdat35a:mov ah,setattr ; set file date/time attributes
mov al,1 ; set, not get
mov bx,diskio.handle ; file handle
int dos ; end of file attributes
rdat35b:mov ah,close2 ; DOS 2.0 file close
mov bx,diskio.handle ; file handle
int dos
pop bx
mov filopn,0 ; File closed now
rdat36: cmp flags.destflg,0 ; Writing to printer?
jne rdat37 ; ne = no, skip next part
cmp flags.xflg,1 ; Writing to screen?
je rdat37 ; Yes, skip this part
mov dl,ff ; Send a form feed
mov ah,lstout ; Write out to first printer
int dos
rdat37: mov pack.numtry,0 ; Reset the number of tries
mov pack.datlen,0 ; No data. (The packet number is in seqnum.)
call ackpak ; acknowledge the packet
mov pack.state,'F'
mov ax,0 ; tell statistics this was a receive operation
call endtim ; get tod & size of file transfer
ret
rdata4: cmp ah,'M' ; Message packet?
jne rdata4e ; ne = no
call dodec ; decode it
jmp error1 ; display it and return
rdata4e: cmp ah,'E' ; Is it an error packet?
jne rdata5 ; ne = no
call error
rdata5: jmp abort
RDATA ENDP
; Error exit. Enter with dx pointing to error message. [jrd]
rcverr proc near
test flags.remflg,dquiet ; quiet display mode?
jnz rcver1 ; nz = yes. Don't write to screen
cmp flags.destflg,2 ; Receiving to the screen?
je rcver1 ; e = yes, no formatted display
call erpos ; Position cursor
mov ah,prstr
int dos ; Print an error message
rcver1: mov bx,dx ; set bx to error message
call errpack ; Send error packet just in case
jmp abort ; Change the state to abort
rcverr endp
; Called by GETATT in receiver code to verify sufficient disk space.
; Gets file path from diskio.string setup in mssfil, remote size in ofilsz
; from getatt, and whether a disk file or not via ioctl on the file handle.
; Returns carry clear if enough space.
spchk proc near ; check for enough disk space
push ax
push bx
push cx
push dx
mov ah,ioctl ; ask DOS about this file handle
mov al,0 ; get info
mov bx,diskio.handle
int dos
test dl,80h ; handle is a disk file?
jnz spchk5b ; nz = no, always enough space
inc dl
and dl,01fh ; get current drive from bits 5-0
mov ah,36h ; get disk free space
int dos
cmp ax,0ffffh ; error response?
je spchk6 ; e = yes
mul bx ; sectors/cluster * clusters = sectors
mov bx,dx ; save high word of sectors (> 64K)
mul cx ; bytes = sectors * bytes/sector
push ax ; save low word of bytes
mov ax,bx ; recall sectors high word
mov bx,dx ; save current bytes high word
mul cx ; high word sectors * bytes/sector
add ax,bx ; new high bytes + old high bytes
push ax ; save high word, dx:ax
mov dx,ofilsz ; high word of file size dx:ax
mov ax,ofilsz+2 ; low word
mov cx,dx ; copy size long word to cx:bx
mov bx,ax
shr bx,1 ; divide long word by two
shr cx,1
jnc spchk2 ; nc = no carry down
or bx,8000h ; get carry down
spchk2: shr bx,1 ; divide by two again
shr cx,1
jnc spchk3
or bx,8000h ; get carry down
spchk3: shr bx,1 ; divide long word by two
shr cx,1
jnc spchk4 ; nc = no carry down
or bx,8000h ; get carry down
spchk4: shr bx,1 ; divide long word by two
shr cx,1
jnc spchk5 ; nc = no carry down
or bx,8000h ; get carry down
spchk5: add ax,bx ; form dx:ax = (17/16) * dx:ax
adc dx,cx
spchk5a:pop cx ; high word of disk space
pop bx ; low word
sub bx,ax ; minus inflated file size, low word
sbb cx,dx ; and high word
js spchk6 ; s = not enough space for file
spchk5b:clc
jmp short spchk7 ; enough space
spchk6: call erpos ; Position cursor
mov ah,prstr
mov dx,offset erms11 ; Not enough space for file
int dos
stc
spchk7: pop dx
pop cx
pop bx
pop ax
ret
spchk endp
; Jumping to this location is like retskp. It assumes the instruction
; after the call is a jmp addr
RSKP PROC NEAR
pop bp
add bp,3
push bp
ret
RSKP ENDP
code ends
end